//
//  MailWarnMe.m
//  MailWarnMe
//
//  Created by Chaim Peck on 3/2/11.
//  Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "MailWarnMe.h"

#import <objc/runtime.h>
#import <WebKit/WebKit.h>
#import "MailHeaders.h"

@interface ObjectForPredicate : NSObject
{
	NSString *recipient;
	NSString *sender;
}

@property (readonly,retain) NSString *recipient;
@property (readonly,retain) NSString *sender;

- (id) initWithRecipient:(NSString *)recipient sender:(NSString *)sender;

@end

@implementation ObjectForPredicate

@synthesize recipient;
@synthesize sender;

- (id) initWithRecipient:(NSString *)aRecipient sender:(NSString *)aSender {
	self = [super init];
	if (self) {
		[recipient autorelease];
		recipient = [aRecipient retain];
		
		[sender autorelease];
		sender = [aSender retain];
	}
	return self;
}

- (void) dealloc {
    [recipient release];
    [sender release];
    [super dealloc];
}

@end



@interface ComposeBackEnd (MailWarnMe)

- (NSMutableArray *)recipients;
- (NSMutableArray *)toRecipients;
- (NSMutableArray *)ccRecipients;
- (NSMutableArray *)bccRecipients;
- (NSString *)sender;

@end

@interface MailWarnMe (MailWarnMe)

- (ComposeBackEnd *) backEnd;
+ (void) registerBundle;
- (void) _send:(id)arg1;

@end


@implementation MailWarnMe

- (NSArray *)allRecipientsArray {
	ComposeBackEnd *backend;
	
	if ([self respondsToSelector:@selector(backEnd)])
		backend = [self backEnd];
	else
		NSLog(@"ERROR");
	
	NSMutableArray *allRecipients = [NSMutableArray array];
	NSMutableArray *recipients = [NSMutableArray array];
	NSMutableArray *toRecipients = [NSMutableArray array];
	NSMutableArray *ccRecipients = [NSMutableArray array];
	NSMutableArray *bccRecipients = [NSMutableArray array];
	
	if ([backend respondsToSelector:@selector(recipients)] == YES)
		recipients = [backend recipients];
	
	if ([backend respondsToSelector:@selector(toRecipients)] == YES)
		toRecipients = [backend toRecipients];
	
	if ([backend respondsToSelector:@selector(ccRecipients)] == YES)
		ccRecipients = [backend ccRecipients];
	
	if ([backend respondsToSelector:@selector(bccRecipients)] == YES)
		bccRecipients = [backend bccRecipients];
	
	NSMutableArray* aRecipientArray;
	
	for (aRecipientArray in [NSArray arrayWithObjects:recipients, toRecipients, ccRecipients, bccRecipients, nil]) {
		NSEnumerator *e = [aRecipientArray objectEnumerator];
		id messageAddressee;
		
		while (messageAddressee = [e nextObject]) {
			[allRecipients addObject:[messageAddressee address]];
		}
	}
	
	return [NSArray arrayWithArray:allRecipients];
}

- (NSString *) senderString {
	ComposeBackEnd *backend;
	
	if ([self respondsToSelector:@selector(backEnd)])
		backend = [self backEnd];
	else
		NSLog(@"ERROR");
	
	NSString *sender;
	
	if ([backend respondsToSelector:@selector(ccRecipients)] == YES)
		sender = [backend sender];
	else 
		NSLog(@"ERROR");
	
	return [NSString stringWithString:sender];
}


void describeObject(id obj) {
	NSLog(@"MailWarnMe: describeObject");
	
	NSMutableString *description = [NSMutableString string];
	
	Class class = object_getClass(obj);
	unsigned int numMethods;
	NSString *className = [NSString stringWithCString:class_getName(class) encoding:NSASCIIStringEncoding];
	Method *methods = class_copyMethodList(class,&numMethods);
						   
	[description appendFormat:@"%@ - Num Methods: %u\n", className, numMethods];
	
	for (int i = 0; i < numMethods; i++) {
		[description appendFormat:@"%@\n", NSStringFromSelector(method_getName(methods[i]))];
	}
	
	NSLog(@"%@",description);
}

void _send_(id self, SEL _cmd, id arg1) {
	NSLog(@"MailWarnMe send");
	
	NSArray *recipientsArray = [self allRecipientsArray];
	NSString *senderString = [self senderString];
	
	NSLog(@"recipients: %@",[recipientsArray componentsJoinedByString:@", "]);
	NSLog(@"sender: %@",senderString);
	
	NSMutableArray *objectsForPredicate = [NSMutableArray array];
	
	NSString *recipient;
	
	for (recipient in recipientsArray) {
		ObjectForPredicate *obj = [[ObjectForPredicate alloc] initWithRecipient:recipient sender:senderString];
		
		NSLog(@"About to add recipient %@",recipient);
		
		[objectsForPredicate addObject:obj];
	}
	
	NSLog(@"%d object(s) for predicate",[objectsForPredicate count]);
	
	
	NSData *myPredicateData = [[NSUserDefaults standardUserDefaults] objectForKey:@"predicate"];
	
	NSPredicate* myPredicate = [NSKeyedUnarchiver unarchiveObjectWithData:myPredicateData];
	
	NSLog(@"My predicate: %@",myPredicate);
	
	[objectsForPredicate filterUsingPredicate:myPredicate];
	
	NSLog(@"Predicate filter applied");
	
	NSLog(@"Now %d object(s) after predicate applied",[objectsForPredicate count]);
	
	if ([objectsForPredicate count] > 0) {
		NSString *warningMessage = [[NSUserDefaults standardUserDefaults] objectForKey:@"warningMessage"];
		
		NSAlert *alert = [[[NSAlert alloc] init] autorelease];
		[alert addButtonWithTitle:@"Send Anyway"];
		[alert addButtonWithTitle:@"Cancel"];
		[alert setMessageText:@"Warning: MailWarnMe Says..."];
		[alert setInformativeText:warningMessage];
		[alert setAlertStyle:NSCriticalAlertStyle];
		[alert beginSheetModalForWindow:[self window] modalDelegate:self didEndSelector:@selector(warningDidEnd:returnCode:contextInfo:) contextInfo:arg1];
	}
	else {
		[self _send: arg1];
	}
}

- (void) warningDidEnd:(NSAlert *)alert returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {	
	if (returnCode == NSAlertFirstButtonReturn) {
		[self _send: contextInfo];
	}
}
		
		
/*
 * The following method is from here: http://sourceforge.jp/projects/letter-fix/svn/view/letter-fix/LetterFix.m?view=markup&revision=9&root=letter-fix&sortby=date
 * Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
 */
void swizzlingMethod(Class aClass, SEL aSelector, SEL nSelector, IMP nImplement) {
    Method orig_method, alt_method;
    
    if ((orig_method = class_getInstanceMethod(aClass, aSelector)) == NULL) {
		NSLog(@"Swizzling Method: Original Method is not found.");
		return; // Original Method is not found.
    }
    // If orig_method was the superclass's instance method, so now we'll add the implement as method of self class.
    if (class_addMethod(aClass, aSelector, method_getImplementation(orig_method), method_getTypeEncoding(orig_method)) == YES) {
		orig_method = class_getInstanceMethod(aClass, aSelector);
    }
    if (class_addMethod(aClass, nSelector, nImplement, method_getTypeEncoding(orig_method)) == NO) {
		NSLog(@"Swizzling Method: Can't add new method.");
		return; // Can't add new method
    }
    alt_method  = class_getInstanceMethod(aClass, nSelector);
    method_exchangeImplementations(orig_method, alt_method);
    //NSLog(@"Swizzling Method: Success.");
}

+ (void) addMethodSelector:(SEL)selector toClass:(Class)class  {
	Method method = class_getInstanceMethod([self class], selector);
	class_addMethod(class, method_getName(method), method_getImplementation(method), method_getTypeEncoding(method));
}

+ (void) initialize {
	[super initialize];
	
	Class mvMailBundleClass = NSClassFromString(@"MVMailBundle");
	
	if(!mvMailBundleClass) {
		NSLog(@"MailWarnMe ERROR: Could not get MVMailBundle class");
	}
	else {
		class_setSuperclass([self class], mvMailBundleClass);
		
		[MailWarnMe registerBundle];
		
		Class mailDocumentEditorClass = NSClassFromString(@"MailDocumentEditor");
		
		if(!mailDocumentEditorClass) {
			NSLog(@"MailWarnMe ERROR: Could not get MailDocumentEditor class");
		}
		else {
			
			swizzlingMethod(mailDocumentEditorClass, @selector(send:), @selector(_send:), (IMP)_send_);
			[self addMethodSelector:@selector(warningDidEnd:returnCode:contextInfo:) toClass:mailDocumentEditorClass];
			[self addMethodSelector:@selector(allRecipientsArray) toClass:mailDocumentEditorClass];
			[self addMethodSelector:@selector(senderString) toClass:mailDocumentEditorClass];
			NSLog(@"MailWarnMe is now registered");
		}
	}
}


+ (BOOL) hasPreferencesPanel {
	NSLog(@"hasPreferencesPanel");
	return YES;
}

+ (NSString *) preferencesOwnerClassName {
	NSLog(@"preferencesOwnerClassName");
	return @"MailWarnMePreferencesModule";
}

+ (NSString *) preferencesPanelName {
	NSLog(@"preferencesPanelName");
	return @"MailWarnMe";
}


@end
